package com.free.space.service.invoice;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * 贴票助手
 *
 * @author zlj
 * 201905
 */
@Service
public class CalculateInvoiceService {
    private BigDecimal tmpBigDecimal = new BigDecimal(0);
    private double[] doubleAr = null;
    private static final int COUNT = 20;

    /**
     * 计算发票数量
     *
     * @return
     */
    public String calculateInvoiceNum(String targetAmount, String sourInvoice) {
        targetAmount = clearStr(targetAmount);
        sourInvoice = clearStr(sourInvoice);
        BigDecimal amount = new BigDecimal(targetAmount);
        String[] invoiceArr = sourInvoice.split(",");
        if (invoiceArr.length > COUNT) {
            return "数量太多,不要超过 20 个";
        }
        double[] dArr = strArr2DounArr(invoiceArr);
        BigDecimal invTotle = sumArr(dArr);
        if (invTotle.doubleValue() < amount.doubleValue()) {
            return "金额不足,还需：" + (amount.subtract(invTotle).doubleValue());
        }
        if (invTotle.doubleValue() == amount.doubleValue()) {
            return  " 金额："+invTotle.doubleValue()+" 需要：" + amount.doubleValue();
        }
        return calculate(dArr, amount);
    }

    /**
     * 计算发票数量
     *
     * @param dArr
     * @param amount
     * @return
     */
    private String calculate(double[] dArr, BigDecimal amount) {
        int length = dArr.length;
        int times = (int) (Math.pow(2, length));
        double[] resTmpArr;
        for (int i = 0; i < times; i++) {
            resTmpArr = new double[dArr.length];
            int s = i;
            for (int j = 0; j < length && s > 0; j++) {
                if ((s & 1) == 1) {
                    resTmpArr[j] = dArr[j];
                }
                s = s >> 1;
            }
            if (strArr2DounArr(resTmpArr, amount)) {
                return " 金额：" + amount+" 需要：" + resultStrAppend(resTmpArr);
            }
        }
        return "最接近金额：" + tmpBigDecimal.doubleValue()+" 需要：" + resultStrAppend(doubleAr) ;
    }

    /**
     * 更新缓存金额
     *
     * @param da
     * @param amount
     */
    private void updateCacheArr(double[] da, BigDecimal amount) {
        if (amount.doubleValue() < tmpBigDecimal.doubleValue()
                || tmpBigDecimal.doubleValue() == 0) {
            tmpBigDecimal = amount;
            doubleAr = da;
        }
    }

    /**
     * 计算数组和
     *
     * @param dArr
     * @param amount
     * @return
     */
    private boolean strArr2DounArr(double[] dArr, BigDecimal amount) {
        BigDecimal b = sumArr(dArr);
        if (b.doubleValue() == amount.doubleValue()) {
            return true;
        }
        if (b.doubleValue() > amount.doubleValue()) {
            updateCacheArr(dArr, b);
        }
        return false;
    }

    /**
     * 字符串清理
     *
     * @param str
     * @return
     */
    private String clearStr(String str) {
        str = str.replaceAll("\n", "");
        str = str.replaceAll(" ", "");
        str = str.replaceAll("，", ",");
        str = str.replaceAll(",,", ",");
        return str;
    }

    /**
     * 计算数组和
     *
     * @param dArr
     * @return
     */
    private BigDecimal sumArr(double[] dArr) {
        BigDecimal b = new BigDecimal(0);
        for (double d : dArr) {
            b = b.add(BigDecimal.valueOf(d));
        }
        return b;
    }

    /**
     * 字符串数字转double数组
     *
     * @param invoiceArr
     * @return
     */
    private double[] strArr2DounArr(String[] invoiceArr) {
        double[] dArr = new double[invoiceArr.length];
        for (int i = 0; i < invoiceArr.length; i++) {
            if (null != invoiceArr[i] && !"".equals(invoiceArr[i])) {
                if("0.0".equals(invoiceArr[i])){
                    continue;
                }
                dArr[i] = Double.parseDouble(invoiceArr[i]);
            }
        }
        return dArr;
    }

    /**
     * 数据拼接字符串返回
     * @param dArr
     * @return
     */
    private String resultStrAppend(double[] dArr) {
        StringBuilder sb = new StringBuilder();
        for(double d:dArr){
            if(d == 0){
                continue;
            }
            sb.append(d);
            sb.append(",");
        }
        return sb.toString();
    }

}
